﻿using System;
using System.Collections.Generic;
using System.Text;
using BNSharp;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using BNSharp.BattleNet;
using BNSharp.BattleNet.Stats;
using System.IO;
using Reticle.Core;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Threading;

namespace Reticle
{
    public class Bot
    {
        public int ID { get; private set; }
        public List<string> ChatHTML { get; set; }
        public List<string> OpHTML { get; set; }
        public List<string> UserHTML { get; set; }
        public string BotKey { get; set; }
        public int ChannelUsers { get; set; }
        public string CurrentChannel { get; set; }
        public string BotHome { get; set; }
        public bool ShowJoinLeave { get; set; }
        public bool DisableQueue { get; set; }

        // plugins
        public List<IPlugin> Plugins { get; set; }
        public ToolStripMenuItem PluginMenu { get; set; }

        // queue
        public Queue Queue { get; set; }
        public System.Timers.Timer QTimer { get; private set; }
        public System.Timers.Timer ProcessQ { get; private set; }
        public Int32 QueueTime { get; private set; }

        public BattleNetClient client;

        public Bot(int id, Settings settings, string key, string homechannel)
        {
            ID = id;
            ChatHTML = new List<string>();
            OpHTML = new List<string>();
            UserHTML = new List<string>();
            BotKey = key;
            BotHome = homechannel;
            ShowJoinLeave = false;
            DisableQueue = false;

            Plugins = new List<IPlugin>();
            PluginMenu = new ToolStripMenuItem();

            //queue
            Queue = new Queue();
            QTimer = new System.Timers.Timer();
            QTimer.Elapsed += QTimer_Tick;
            QTimer.Interval = 25;
            ProcessQ = new System.Timers.Timer();
            ProcessQ.Elapsed += ProcessQ_Tick;
            ProcessQ.Interval = 1;
            QueueTime = 4500;

            client = new BattleNetClient(settings);

            client.AccountCreated += new AccountCreationEventHandler(AccountCreated);
            client.AccountCreationFailed += new AccountCreationFailedEventHandler(AccountCreationFailed);
            client.ChannelDidNotExist += new ServerChatEventHandler(ChannelDidNotExist);
            client.ChannelListReceived += new ChannelListEventHandler(ChannelListReceived);
            client.ChannelWasFull += new ServerChatEventHandler(ChannelWasFull);
            client.ClientCheckFailed += new ClientCheckFailedEventHandler(ClientCheckFailed);
            client.ClientCheckPassed += new EventHandler(ClientCheckPassed);
            client.Connected += new EventHandler(Connected);
            client.Disconnected += new EventHandler(Disconnected);
            client.EnteredChat += new EnteredChatEventHandler(EnteredChat);
            client.Error += new BNSharp.ErrorEventHandler(Error);
            client.EventExceptionThrown += new EventExceptionEventHandler(EventExceptionThrown);
            client.Information += new InformationEventHandler(Information);
            client.InformationReceived += new ServerChatEventHandler(InformationReceived);
            client.JoinedChannel += new ServerChatEventHandler(JoinedChannel);
            client.LoginFailed += new LoginFailedEventHandler(LoginFailed);
            client.LoginSucceeded += new EventHandler(LoginSucceeded);
            client.MessageSent += new ChatMessageEventHandler(MessageSent);
            client.ServerBroadcast += new ServerChatEventHandler(ServerBroadcast);
            client.ServerErrorReceived += new ServerChatEventHandler(ServerErrorReceived);
            client.UserEmoted += new ChatMessageEventHandler(UserEmoted);
            client.UserFlagsChanged += new UserEventHandler(UserFlagsChanged);
            client.UserJoined += new UserEventHandler(UserJoined);
            client.UserLeft += new UserEventHandler(UserLeft);
            client.UserShown += new UserEventHandler(UserShown);
            client.UserSpoke += new ChatMessageEventHandler(UserSpoke);
            //client.WardenUnhandled += new EventHandler(WardenUnhandled);
            client.WhisperReceived += new ChatMessageEventHandler(WhisperReceived);
            client.WhisperSent += new ChatMessageEventHandler(WhisperSent);
            client.UserProfileReceived += new UserProfileEventHandler(UserProfileReceived);
        }

        public void Connect()
        {
            client.Connect();

            QTimer.Start();
            ProcessQ.Start();
        }

        public void Disconnect()
        {
            client.Close();

            QTimer.Stop();
            ProcessQ.Stop();
        }

        public void LoadPlugins()
        {
            List<IPlugin> TempPlugins = PluginFunctions.GetAllPluginsBot<IPlugin>();
            //Plugins = PluginFunctions.GetPlugins<IPlugin>(BotKey, Environment.CurrentDirectory + @"\files\plugins\");
            List<string> myPlugins = PluginFunctions.GetMyPlugins(BotKey);

            foreach (IPlugin p in TempPlugins)
            {
                if (myPlugins.Contains(p.Filename) && !IsPluginLoaded(p.Filename))
                {
                    try
                    {
                        p.Initialize(new PluginInterface(this, p));
                    }
                    catch (Exception ex)
                    {
                        string exception = String.Format("Plugin Error ({0}) >> {1}\n{2}\n{3}\n{4}\n{5}\n{6}", p.Name, ex.Message, ex.Source, ex.StackTrace, ex.TargetSite, ex.InnerException, ex.HelpLink);
                        if (BotKey == Program.Window.CurrentTabKey())
                        {
                            Program.Window.InvokeScript(BotKey, Program.Window.checkSetting("chatevent"), String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">{1}</span></div>", Helper.TimeStamp(), exception));
                            Program.Window.AddChat(BotKey, String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">{1}</span></div>", Helper.TimeStamp(), exception));
                        }
                        else
                        {
                            Program.Window.AddChat(BotKey, String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">{1}</span></div>", Helper.TimeStamp(), exception));
                        }
                    }
                    Plugins.Add(p);
                }
            }
        }

        public bool IsPluginLoaded(string filename)
        {
            if (Plugins.Count == 0)
                return false;
            foreach (IPlugin i in Plugins)
            {
                if (i.Filename == filename)
                    return true;
            }
            return false;
        }

        public void CreateMenu()
        {
            if (BotKey == Program.Window.CurrentTabKey())
            {
                ToolStripMenuItem myMenus = new ToolStripMenuItem();
                myMenus.Text = "Plugins";
                myMenus.Name = "menuPlugins";

                if (PluginMenu.DropDownItems.Count > 0)
                {
                    PluginMenu.Text = "Loaded Plugins";
                    // PluginMenu.Name = "Plugins";
                    //PluginMenu.Name = BotKey;
                    //Program.Window.AddPluginMenu(PluginMenu);
                    myMenus.DropDownItems.Add(PluginMenu);
                }

                EventHandler e = new EventHandler(loadPlugin_Click);
                ToolStripMenuItem newPlugin = new ToolStripMenuItem();
                newPlugin.Text = "Load";


                foreach (string file in PluginFunctions.GetAllPlugins())
                {
                    //newPlugin.DropDownItems.Add(file, null, e);
                    if (IsPluginLoaded(file))
                    {
                        newPlugin.DropDownItems.Add(PluginFunctions.NewToolMenu(file, file, e, true));
                    }
                    else
                    {
                        newPlugin.DropDownItems.Add(PluginFunctions.NewToolMenu(file, file, e, false));
                    }
                }

                myMenus.DropDownItems.Add(newPlugin);

                // create the "View Available plugins"
                ToolStripSeparator sep1 = new ToolStripSeparator();
                myMenus.DropDownItems.Add(sep1);

                EventHandler p = new EventHandler(availablePlugin_Click);
                ToolStripMenuItem viewPlugins = new ToolStripMenuItem();
                viewPlugins.Text = "Available Plugins";
                myMenus.DropDownItems.Add(PluginFunctions.NewToolMenu("Available", "Available Plugins", p));

                //Program.Window.AddPluginMenu(newPlugin);
                //PluginMenu.DropDownItems.Add(newPlugin);
                Program.Window.AddPluginMenu(myMenus);
            }
        }

        public void availablePlugin_Click(object sender, EventArgs e)
        {
            GlobalSettings settings = new GlobalSettings(Program.Window.CurrentTabKey(), 1);
            settings.ShowDialog();
        }

        public void loadPlugin_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem m = (ToolStripMenuItem)sender;

            List<IPlugin> plugin = PluginFunctions.GetSinglePlugin<IPlugin>(BotKey, String.Format(@"{0}\files\plugins\{1}", Application.StartupPath, m.Name));
            foreach (IPlugin p in plugin)
            {
                if (p.Filename == m.Name)
                {
                    try
                    {
                        if (IsPluginLoaded(p.Filename))
                        {
                            break;
                        }
                        p.Initialize(new PluginInterface(this, p));
                    }
                    catch (Exception)
                    {
                        Debug.Print("Did not initialize.");
                    }
                }
            }
        }

        public void Enqueue(string message)
        {
            if (Queue.Contains(message))
                return;

            Queue.Enqueue(message);
        }

        public void ClearQueue()
        {
            Queue.Clear();
        }

        public void QTimer_Tick(object sender, EventArgs e)
        {
            if (QueueTime >= 16000)
            {
                QueueTime = 16000;
                QTimer.Stop();
            }
            else
            {
                QueueTime += 25;
            }
        }

        public void ProcessQ_Tick(object sender, EventArgs e)
        {
            if (QueueTime < 16000)
                QTimer.Start();

            if (Queue.Count == 0)
                return;

            string message = (string)Queue.Peek();
            Int32 wait = WaitTime(message);
            if (QueueTime - wait >= 0)
            {
                message = (string)Queue.Dequeue();
                QueueTime -= wait;
                SendMessage(message);
            }
        }

        Int32 WaitTime(string message)
        {
            // If user has disabled the queue
            if (DisableQueue)
            {
                return 1;
            }

            if (message.Length < 31)
                return 3800;
            else if (message.Length < 61 && message.Length > 30)
                return 4100;
            else if (message.Length < 91 && message.Length > 60)
                return 7000;
            else if (message.Length < 121 && message.Length > 90)
                return 8500;
            else if (message.Length < 180 && message.Length > 120)
                return 9000;
            else
                return 10000;
        }

        public void SendMessage(string text)
        {
            try
            {
                if (client.IsConnected)
                {
                    if (text.Substring(0, 1) == "/")
                    {
                        text = Commands.ProcessCommand(text, this);
                    }

                    if (text != null)
                    {
                        client.SendMessage(text);
                    }
                }
            }
            catch (Exception) { }
        }

        public void ReloadSettings(Settings settings)
        {
            client.Settings.Username = settings.Username;
            client.Settings.Password = settings.Password;
            client.Settings.CdKey1 = settings.CdKey1;
            if (settings.CdKey2 != "")
            {
                client.Settings.CdKey2 = settings.CdKey2;
            }
            client.Settings.Server = settings.Server;
            client.Settings.HomeChannel = settings.HomeChannel;
            client.Settings.Client = settings.Client;
            client.Settings.CdKeyOwner = settings.Username;
        }

        // Fix Diablo II usernames
        public string FixUsername(string username)
        {
            if (username.StartsWith("*"))
            {
                return username.Replace("*", "");
            }

            return username;
        }

        // check hashes for speific product and output to chat screen
        public bool checkHashesBot(string product)
        {
            bool download = false;
            switch (product)
            {
                //STAR/SEXP
                case "STAR":
                case "SEXP":
                    if (Manager.CheckConfigHashes("STAR") == false)
                    {
                        HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[Hashes] Starcraft/Broodwar hashes not found.</span> <span class=\"yellow\">Attempting to download...</span></div>", Helper.TimeStamp()));
                        download = true;
                    }
                    break;
                case "W2BN":
                    if (Manager.CheckConfigHashes("W2BN") == false)
                    {
                        HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[Hashes] Warcraft II: BNE hashes not found.</span> <span class=\"yellow\">Attempting to download...</span></div>", Helper.TimeStamp()));
                        download = true;
                    }
                    break;
                case "D2DV":
                    if (Manager.CheckConfigHashes("D2DV") == false)
                    {
                        HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[Hashes] Diablo II hashes not found.</span> <span class=\"yellow\">Attempting to download...</span></div>", Helper.TimeStamp()));
                        download = true;
                    }
                    break;
                case "D2XP":
                    if (Manager.CheckConfigHashes("D2XP") == false)
                    {
                        HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[Hashes] Diablo II: Lord of Destruction hashes not found.</span> <span class=\"yellow\">Attempting to download...</span></div>", Helper.TimeStamp()));
                        download = true;
                    }
                    break;
                case "WAR3":
                case "W3XP":
                    if (Manager.CheckConfigHashes("WAR3") == false)
                    {
                        HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[Hashes] Warcraft III/The Frozen Throne hashes not found.</span> <span class=\"yellow\">Attempting to download...</span></div>", Helper.TimeStamp()));
                        download = true;
                    }
                    break;
            }

            // attempt to download the hashes
            if (download)
            {
                Thread thread = new Thread(new ParameterizedThreadStart(Manager.DownloadHashes));
                thread.Start(client.Settings.Client);
                return false;
            }

            return true;
        }

        public void RequestProfile(string username)
        {
            UserProfileRequest request = new UserProfileRequest(username, UserProfileKey.Sex, UserProfileKey.Location, UserProfileKey.Description,
                            UserProfileKey.AccountCreated, UserProfileKey.LastLogon, UserProfileKey.LastLogoff, UserProfileKey.TotalTimeLogged);

            client.RequestUserProfile("Scope", request);
        }

        public bool IsConnected()
        {
            if (client.IsConnected)
            {
                return true;
            }

            return false;
        }

        private void UserProfileReceived(object sender, UserProfileEventArgs e)
        {
            List<string> nodesToAdd = new List<string>();
            foreach (UserProfileKey key in e.Profile)
            {
                if (key.Equals(UserProfileKey.TotalTimeLogged))
                {
                    int totalSeconds;
                    if (int.TryParse(e.Profile[key], out totalSeconds))
                    {
                        TimeSpan ts = TimeSpan.FromSeconds(totalSeconds);
                        nodesToAdd.Add(string.Format("{0} day{4}, {1} hour{5}, {2} minute{6}, {3} second{7}.",
                            (int)ts.TotalDays, ts.Hours, ts.Minutes, ts.Seconds, ((int)ts.TotalDays == 1) ? string.Empty : "s",
                            ts.Hours == 1 ? string.Empty : "s", ts.Minutes == 1 ? string.Empty : "s", ts.Seconds == 1 ? string.Empty : "s"));
                    }
                    else
                    {
                        nodesToAdd.Add(e.Profile[key]);
                    }
                }
                else
                {
                    nodesToAdd.Add(e.Profile[key]);
                }
            }

            foreach (string x in nodesToAdd)
            {
                MessageBox.Show(x);
            }
        }

        // send blah blah to the bots chat screen and/or its container list
        public void HandleChat(string message)
        {
            if (BotKey == Program.Window.CurrentTabKey())
            {
                Program.Window.InvokeScript(BotKey, Program.Window.checkSetting("chatevent"), message);
                Program.Window.AddChat(BotKey, message);
            }
            else
            {
                Program.Window.AddChat(BotKey, message);
            }
        }

        private void AccountCreated(object sender, AccountCreationEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"green\">[BNET] Account Created</span></div>", Helper.TimeStamp()));
        }

        private void AccountCreationFailed(object sender, AccountCreationFailedEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[BNET] Account Creation Failed (</span><span class=\"yellow\">{1}</span><span class=\"red\">)</span></div>", Helper.TimeStamp(), e.Reason));
           
            Program.Window.TabIcon(1, BotKey);
        }

        public void ChannelDidNotExist(object sender, ServerChatEventArgs e)
        {
            
        }

        public void ChannelListReceived(object sender, ChannelListEventArgs e)
        {
           
        }

        public void ChannelWasFull(object sender, ServerChatEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[BNET] Channel is full.</span></div>", Helper.TimeStamp()));
        }

        public void ChannelWasRestricted(object sender, ServerChatEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[BNET] Channel is restricted.</span></div>", Helper.TimeStamp()));
        }

        private void ClientCheckFailed(object sender, ClientCheckFailedEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[BNET] Client Check Failed. (</span><span class=\"yellow\">{1}</span><span class=\"red\">)</span></div>", Helper.TimeStamp(), e.Reason));

            // Attempt to update verbyte/hashes if invalid version
            if (e.Reason.ToString().ToLower().Contains("invalidversion"))
            {
                HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"yellow\">Attempting to update your verbyte/hashes...</span></div>", Helper.TimeStamp(), e.Reason));
                Thread verbytes = new Thread(new ThreadStart(Manager.FetchVerbytes));
                verbytes.Start();

                Thread hashes = new Thread(new ParameterizedThreadStart(Manager.DownloadHashes));
                hashes.Start(client.Settings.Client);
            }
            
            Program.Window.TabIcon(1, BotKey);
        }

        private void ClientCheckPassed(object sender, EventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"green\">[BNET] Client Check Passed</span></div>", Helper.TimeStamp()));
        }

        private void Connected(object sender, EventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"green\">[BNET] Connected</span></div>", Helper.TimeStamp()));

            Program.Window.TabIcon(0, BotKey);
        }

        private void Disconnected(object sender, EventArgs e)
        {
            Program.Window.ClearChannel(BotKey);

            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[BNET] Disconnected</span></div>", Helper.TimeStamp()));
           
            Program.Window.TabIcon(1, BotKey);
        }

        private void EnteredChat(object sender, EnteredChatEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"green\">[BNET] Entered Chat</span></div>", Helper.TimeStamp()));
            
            SendMessage("/j " + BotHome);
        }

        private void Error(object sender, BNSharp.ErrorEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">Error: (</span><span class=\"yellow\">{1}</span><span class=\"red\">) {2}</span></div>", Helper.TimeStamp(), e.Reason, e.Error));
        }

        private void EventExceptionThrown(object sender, EventExceptionEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">Event Exception Thrown: (</span><span class=\"yellow\">{1}</span><span class=\"red\">) {2}</span></div>", Helper.TimeStamp(), e.EventName, e.Exception));
        }

        private void Information(object sender, InformationEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"yellow\">{1}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(e.Information)));
        }

        private void InformationReceived(object sender, ServerChatEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"yellow\">{1}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(e.Text)));
        }

        private void JoinedChannel(object sender, ServerChatEventArgs e)
        {
            Program.Window.ClearChannel(BotKey);

            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-joined-channel-message\">Joined Channel: </span><span id=\"color-joined-channel-name\">{1}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(e.Text)));
            
            ChannelUsers = 0;
            CurrentChannel = e.Text;
        }

        private void LoginFailed(object sender, LoginFailedEventArgs e)
        {
            client.CreateAccount();
        }

        private void LoginSucceeded(object sender, EventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"green\">[BNET] Login Successful</span></div>", Helper.TimeStamp()));
        }

        private void MessageSent(object sender, ChatMessageEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-username-self-talk\">&laquo;{1}&raquo;</span> <span id=\"color-text-self-talk\">{2}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.Username)), Helper.ConvertUrlsToLinks(Helper.ConvertHTML(e.Text))));
        }

        private void ServerBroadcast(object sender, ServerChatEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"gray\">{1}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(e.Text)));
        }

        private void ServerErrorReceived(object sender, ServerChatEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span class=\"red\">[BNET] {1}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(e.Text)));
        }

        private void UserEmoted(object sender, ChatMessageEventArgs e)
        {
            Program.Window.Notify(FixUsername(e.Username), e.Text, "emote");

            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-emote\">&laquo;{1} {2}&raquo;</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.Username)), Helper.ConvertUrlsToLinks(Helper.ConvertHTML(e.Text))));

            // Only set "new" icon if tab isn't selected
            if (BotKey != Program.Window.CurrentTabKey())
            {
                Program.Window.TabIcon(2, BotKey);
            }
        }

        private void UserFlagsChanged(object sender, UserEventArgs e)
        {
            if ((e.User.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator)
            {
                if (BotKey == Program.Window.CurrentTabKey())
                {
                    Program.Window.InvokeScript(BotKey, "removeUser", Helper.ConvertForID(FixUsername(e.User.Username)));
                    OpHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //OpHTML.Remove("<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                    UserHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), e.User.Stats.Product.ProductCode.ToLower(), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //UserHTML.Remove("<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\" + e.User.Stats.Product.ProductCode.ToLower() + ".bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");

                    Program.Window.InvokeScript(BotKey, "addOperator", String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "opfirst");
                }
                else
                {
                    OpHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    UserHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), e.User.Stats.Product.ProductCode.ToLower(), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //OpHTML.Remove("<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                    //UserHTML.Remove("<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\" + e.User.Stats.Product.ProductCode.ToLower() + ".bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");

                    //Program.Window.AddUser(ID, "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>", "op");
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "op");
                }
            }
        }

        private void UserJoined(object sender, UserEventArgs e)
        {
            UserStats us = e.User.Stats;
            string joinedText = "";
            string icon = us.Product.ProductCode.ToLower();
            switch (us.Product.ProductCode)
            {
                case "DRTL":
                case "DSHR":
                case "SSHR":
                case "STAR":
                case "SEXP":
                case "JSTR":
                case "W2BN":
                    StarcraftStats ss = us as StarcraftStats;
                    if (ss == null)
                    {
                        joinedText = String.Format(" has joined the channel using {0}.", us.Product.Name);
                    }
                    else
                    {
                        joinedText = String.Format(" has joined the channel using {0} with {1} win{2}.", ss.Product.Name, ss.Wins, ss.Wins != 1 ? "s" : string.Empty);

                        if ((icon == "star" && client.Settings.Client == "STAR"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "star");
                        }
                        else if ((icon == "sexp" && client.Settings.Client == "SEXP"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "star");
                        }
                        else if ((icon == "w2bn" && client.Settings.Client == "W2BN"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "w2bn");
                        }
                    }
                    break;
                case "D2DV":
                case "D2XP":
                    Diablo2Stats ds = us as Diablo2Stats;
                    if (ds == null)
                    {
                        joinedText = String.Format(" has joined the channel using {0}.", us.Product.Name);
                    }
                    else
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.Append(" has joined the channel using ");
                        sb.Append(ds.Product.Name);
                        if (ds.IsRealmCharacter)
                        {
                            sb.Append(" as ");
                            sb.Append(ds.CharacterName);
                            sb.AppendFormat(", a level {0}", ds.Level);
                            if (ds.IsHardcoreCharacter)
                                sb.Append(" hardcore");
                            if (ds.IsLadderCharacter)
                                sb.Append(" ladder");
                            if (ds.IsExpansionCharacter)
                                sb.Append(" Expansion ");
                            else
                                sb.Append(" Classic ");
                            sb.Append(ds.CharacterClass);
                            sb.Append(".");

                            joinedText = sb.ToString();
                        }
                        else
                        {
                            joinedText = String.Format(" has joined the channel using {0}.", us.Product.Name);
                        }
                    }
                    break;
                case "WAR3":
                case "W3XP":
                    Warcraft3Stats ws = us as Warcraft3Stats;
                    if (ws == null)
                    {
                        joinedText = String.Format(" has joined the channel using {0}.", us.Product.Name);
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(ws.ClanTag))
                        {
                            joinedText = String.Format(" has joined the channel using {0}, a level {1} {2}.", ws.Product.Name, ws.Level, ws.IconRace);
                            //chat.AddChat(new ChatNode(user.Username, CssClasses.UsernameOther), productNode, new ChatNode(string.Format(" joined the channel with {0}, {1} icon tier {2}, level {3}.", ws.Product.Name, ws.IconRace, ws.IconTier, ws.Level), CssClasses.JoinedChannel));
                        }
                        else
                        {
                            joinedText = String.Format(" has joined the channel using {0}, representing Clan {1}, a level {2} {3}.", ws.Product.Name, ws.ClanTag, ws.Level, ws.IconRace);
                            //chat.AddChat(new ChatNode(user.Username, CssClasses.UsernameOther), productNode, new ChatNode(string.Format(" of clan {0} joined the channel with {1}, {2} icon tier {3}, level {4}.", ws.ClanTag, ws.Product.Name, ws.IconRace, ws.IconTier, ws.Level), CssClasses.JoinedChannel));
                        }
                    }
                    break;
            }
            
            ChannelUsers++;

            if (BotKey == Program.Window.CurrentTabKey())
            {
                Program.Window.ChannelName(BotKey, CurrentChannel, ChannelUsers);

                // Show (or don't) join message)
                if (ShowJoinLeave)
                {
                    HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-username-join\">{1}</span> <span id=\"color-joined-channel\">{2}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.User.Username)), joinedText));
                }

                // if operator
                if ((e.User.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator)
                {
                    Program.Window.InvokeScript(BotKey, "addOperator", String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "op");
                    
                    //Program.Window.InvokeScript(BotKey, "addOperator", "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                    //Program.Window.AddUser(ID, "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>", "op");
                }
                else
                {
                    Program.Window.InvokeScript(BotKey, "addUser", String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), icon, FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), icon, FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "user");
                }
            }
            else
            {
                // Show (or don't) join message)
                if (ShowJoinLeave)
                {
                    HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-username-join\">{1}</span> <span id=\"color-joined-channel\">{2}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.User.Username)), joinedText));
                    
                    //Program.Window.AddChat(BotKey, "<div id=\"chattext\"><span id=\"timestamp\">" + Helper.TimeStamp() + "</span><span id=\"color-username-join\">" + Helper.ConvertHTML(e.User.Username) + "</span> <span id=\"color-joined-channel\">" + joinedText + "</span></div>");
                }

                // if operator
                if ((e.User.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator)
                {
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "op");
                    //Program.Window.AddUser(ID, "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>", "op");
                }
                else
                {
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), icon, FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "user");
                    //Program.Window.AddUser(ID, "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\" + icon + ".bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>", "user");
                }
            }

            // Only set "new" icon if tab isn't selected
            if (BotKey != Program.Window.CurrentTabKey() && ShowJoinLeave)
            {
                Program.Window.TabIcon(2, BotKey);
            }
        }

        private void UserLeft(object sender, UserEventArgs e)
        {
            ChannelUsers--;
            
            UserStats us = e.User.Stats;
            string icon = us.Product.ProductCode.ToLower();
            switch (us.Product.ProductCode)
            {
                case "DRTL":
                case "DSHR":
                case "SSHR":
                case "STAR":
                case "SEXP":
                case "JSTR":
                case "W2BN":
                    StarcraftStats ss = us as StarcraftStats;
                    if (ss != null)
                    {
                        if ((icon == "star" && client.Settings.Client == "STAR"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "star");
                        }
                        else if ((icon == "sexp" && client.Settings.Client == "SEXP"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "star");
                        }
                        else if ((icon == "w2bn" && client.Settings.Client == "W2BN"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "w2bn");
                        }
                    }
                    break;
            }

            if (BotKey == Program.Window.CurrentTabKey())
            {
                Program.Window.ChannelName(BotKey, CurrentChannel, ChannelUsers);

                // if operator
                if ((e.User.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator)
                {
       //Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(e.User.Username), e.User.Username, Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "op");
                    OpHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //OpHTML.Remove("<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                }
                else
                {
         //Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(e.User.Username), icon, e.User.Username, Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "user");
                    UserHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), icon, FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //UserHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(e.User.Username), e.User.Stats.Product.ProductCode.ToLower(), e.User.Username, Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //UserHTML.Remove("<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\" + icon + ".bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                }

                // Show (or don't) leave message)
                if (ShowJoinLeave)
                {
                    HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-username-leave\">{1}</span> <span id=\"color-left-channel\">has left the channel.</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.User.Username))));
                    
                    //Program.Window.InvokeScript(BotKey, Program.Window.checkSetting("chatevent"), "<div id=\"chattext\"><span id=\"timestamp\">" + Helper.TimeStamp() + "</span><span id=\"color-username-leave\">" + Helper.ConvertHTML(e.User.Username) + "</span> <span id=\"color-left-channel\">has left the channel.</span></div>");
                    //Program.Window.AddChat(BotKey, "<div id=\"chattext\"><span id=\"timestamp\">" + Helper.TimeStamp() + "</span><span id=\"color-username-leave\">" + Helper.ConvertHTML(e.User.Username) + "</span> <span id=\"color-left-channel\">has left the channel.</span></div>");
                }
                // remove user from list using jQuery (if the tab is the selected tab)
                Program.Window.InvokeScript(BotKey, "removeUser", Helper.ConvertForID(FixUsername(e.User.Username)));
            }
            else
            {
                // if operator
                if ((e.User.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator)
                {
       //Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(e.User.Username), e.User.Username, Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "op");
                    OpHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //OpHTML.Remove("<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                }
                else
                {
         //Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(e.User.Username), icon, e.User.Username, Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "user");
                    UserHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), icon, FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //UserHTML.Remove(String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(e.User.Username), e.User.Stats.Product.ProductCode.ToLower(), e.User.Username, Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    //UserHTML.Remove("<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\" + icon + ".bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                }

                // Show (or don't) leave message)
                if (ShowJoinLeave)
                {
                    HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-username-leave\">{1}</span> <span id=\"color-left-channel\">has left the channel.</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.User.Username))));
                    
                    //Program.Window.AddChat(BotKey, "<div id=\"chattext\"><span id=\"timestamp\">" + Helper.TimeStamp() + "</span><span id=\"color-username-leave\">" + Helper.ConvertHTML(e.User.Username) + "</span> <span id=\"color-left-channel\">has left the channel.</span></div>");
                }
            }

            // Only set "new" icon if tab isn't selected
            if (BotKey != Program.Window.CurrentTabKey() && ShowJoinLeave)
            {
                Program.Window.TabIcon(2, BotKey);
            }
        }

        private void UserShown(object sender, UserEventArgs e)
        {
            ChannelUsers++;

            UserStats us = e.User.Stats;
            string icon = us.Product.ProductCode.ToLower();
            switch (us.Product.ProductCode)
            {
                case "DRTL":
                case "DSHR":
                case "SSHR":
                case "STAR":
                case "SEXP":
                case "JSTR":
                case "W2BN":
                    StarcraftStats ss = us as StarcraftStats;
                    if (ss != null)
                    {
                        if ((icon == "star" && client.Settings.Client == "STAR"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "sexp");
                        }
                        else if ((icon == "sexp" && client.Settings.Client == "SEXP"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "sexp");
                        }
                        else if ((icon == "w2bn" && client.Settings.Client == "W2BN"))
                        {
                            icon = Manager.GetClientIcon(ss.Wins, "w2bn");
                        }
                    }
                    break;
            }

            if (BotKey == Program.Window.CurrentTabKey())
            {
                Program.Window.ChannelName(BotKey, CurrentChannel, ChannelUsers);

                // if operator
                if ((e.User.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator)
                {
                    Program.Window.InvokeScript(BotKey, "addOperator", String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "op");
                    
                    //Program.Window.InvokeScript(BotKey, "addOperator", "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                    //Program.Window.AddUser(ID, "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>", "opfirst");
                }
                else
                {
                    Program.Window.InvokeScript(BotKey, "addUser", String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), icon, FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping));
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), icon, FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "user");

                    //Program.Window.InvokeScript(BotKey, "addUser", "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\" + icon + ".bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>");
                    //Program.Window.AddUser(ID, "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\" + icon + ".bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>", "user");
                }
            }
            else
            {
                // if operator
                if ((e.User.Flags & UserFlags.ChannelOperator) == UserFlags.ChannelOperator)
                {
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{1}</td><td id=\"clantag\" width=\"9%\">{2}</td><td id=\"{3}\" width=\"9%\">{4}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "op");
                    //Program.Window.AddUser(ID, "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\oper.bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>", "op");
                }
                else
                {
                    Program.Window.AddUser(ID, String.Format("<tr id=\"user-{0}\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\{1}.bmp\" /></td><td id=\"username-channel\" width=\"80%\">{2}</td><td id=\"clantag\" width=\"9%\">{3}</td><td id=\"{4}\" width=\"9%\">{5}</td></tr>", Helper.ConvertForID(FixUsername(e.User.Username)), icon, FixUsername(e.User.Username), Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag"), Helper.FormatPing(e.User.Ping), e.User.Ping), "user");
                    //Program.Window.AddUser(ID, "<tr id=\"user-" + Helper.ConvertForID(e.User.Username) + "\"><td width=\"2%\"><img src=\"..\\css\\images\\icons\\" + icon + ".bmp\" /></td><td id=\"username-channel\" width=\"80%\">" + e.User.Username + "</td><td id=\"clantag\" width=\"9%\">" + Helper.ParseStatstring(e.User.Stats.Product.ProductCode, e.User.Stats.LiteralText, "ClanTag") + "</td><td id=\"" + Helper.FormatPing(e.User.Ping) + "\" width=\"9%\">" + e.User.Ping + "</td></tr>", "user");
                }
            }
        }

        private void UserSpoke(object sender, ChatMessageEventArgs e)
        {
            Program.Window.Notify(FixUsername(e.Username), e.Text, "talk");

            HandleChat(String.Format("<div id=\"chattext\"><span class=\"nowrap\"><span id=\"timestamp\">{0}</span><span id=\"username-normal-chat\">&laquo;{1}&raquo;</span></span><span id=\"color-normal-chat\">{2}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.Username)), Helper.ConvertUrlsToLinks(Helper.ConvertHTML(e.Text))));
            
            // Only set "new" icon if tab isn't selected
            if (BotKey != Program.Window.CurrentTabKey())
            {
                Program.Window.TabIcon(2, BotKey);
            }
        }

        private void WardenUnhandled(object sender, EventArgs e)
        {

        }

        private void WhisperReceived(object sender, ChatMessageEventArgs e)
        {
            Program.Window.Notify("From: " + FixUsername(e.Username), e.Text, "whisper");

            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-whisper-from\">&laquo;From: {1}&raquo;</span> <span id=\"color-whisper-text\">{2}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.Username)), Helper.ConvertUrlsToLinks(Helper.ConvertHTML(e.Text))));

            // Only set "new" icon if tab isn't selected
            if (BotKey != Program.Window.CurrentTabKey())
            {
                Program.Window.TabIcon(2, BotKey);
            }
        }

        private void WhisperSent(object sender, ChatMessageEventArgs e)
        {
            HandleChat(String.Format("<div id=\"chattext\"><span id=\"timestamp\">{0}</span><span id=\"color-whisper-to\">&laquo;To: {1}&raquo;</span> <span id=\"color-whisper-text\">{2}</span></div>", Helper.TimeStamp(), Helper.ConvertHTML(FixUsername(e.Username)), Helper.ConvertUrlsToLinks(Helper.ConvertHTML(e.Text))));
        }
    }

    /* util */
    class Helper
    {
        public static string TimeStamp(string format = "h:mm:ss tt")
        {
            DateTime parsedDate = DateTime.Now;
            string timeStamp = "[" + parsedDate.ToString(format) + "]";
            return timeStamp;
        }

        public static string ConvertHTML(string html)
        {
            //return HttpUtility.HtmlEncode(html);
            return html.Replace("<", "&lt;").Replace(">", "&gt;");
        }

        public static string FormatPing(int ping)
        {
			if (ping == 0)
			{
                return "ping-0";
			}
			else if ((ping > 0) && (ping < 100))
			{
                return "ping-1-99";
			}
			else if ((ping >= 100) && (ping < 200))
			{
                return "ping-100-199";
			}
			else if ((ping >= 200) && (ping < 300))
			{
                return "ping-200-299";
			}
			else if ((ping >= 300) && (ping < 400))
			{
                return "ping-300-399";
			}
			else if ((ping >= 400) && (ping < 500))
			{
                return "ping-400-499";
			}
			else if ((ping >= 500) && (ping < 600))
			{
                return "ping-500-599";
			}
			else
			{
                return "ping-600";
			}
        }

        public static string ParseStatstring(string product, string statstring, string method)
        {
            string[] stats = statstring.Split(new char[] { ' ' });

            if (method == "UserJoin")
            {
                switch (product)
                {
                    case "STAR":
                    case "SEXP":
                        //return " with " + stats[3] + " wins";
                    case "W2BN":
                        return String.Format(" with {0} wins", stats[3]);    
                    default:
                        return null;
                }
            }

            if (method == "ClanTag")
            {
                switch (product)
                {
                    case "WAR3":
                    case "W3XP":
                        if (stats.Length == 4)
                        {
                            return ReverseString(stats[3]);
                        }
                        break;
                    default:
                        return null;
                }
            }

            return null;
        }

        public static string ConvertForID(string username)
        {
            string newString = "";

            foreach (char c in username)
            {
                string x = c.ToString().ToLower();
                switch (x)
                {
                    case "a":
                        newString += "a";
                        break;
                    case "b":
                        newString += "b";
                        break;
                    case "c":
                        newString += "c";
                        break;
                    case "d":
                        newString += "d";
                        break;
                    case "e":
                        newString += "e";
                        break;
                    case "f":
                        newString += "f";
                        break;
                    case "g":
                        newString += "g";
                        break;
                    case "h":
                        newString += "h";
                        break;
                    case "i":
                        newString += "i";
                        break;
                    case "j":
                        newString += "j";
                        break;
                    case "k":
                        newString += "k";
                        break;
                    case "l":
                        newString += "l";
                        break;
                    case "m":
                        newString += "m";
                        break;
                    case "n":
                        newString += "n";
                        break;
                    case "o":
                        newString += "o";
                        break;
                    case "p":
                        newString += "p";
                        break;
                    case "q":
                        newString += "q";
                        break;
                    case "r":
                        newString += "r";
                        break;
                    case "s":
                        newString += "s";
                        break;
                    case "t":
                        newString += "t";
                        break;
                    case "u":
                        newString += "u";
                        break;
                    case "v":
                        newString += "v";
                        break;
                    case "w":
                        newString += "w";
                        break;
                    case "x":
                        newString += "x";
                        break;
                    case "y":
                        newString += "y";
                        break;
                    case "z":
                        newString += "z";
                        break;
                    case "~":
                        newString += "1";
                        break;
                    case "`":
                        newString += "2";
                        break;
                    case "!":
                        newString += "3";
                        break;
                    case "@":
                        newString += "4";
                        break;
                    case "#":
                        newString += "5";
                        break;
                    case "$":
                        newString += "6";
                        break;
                    case "^":
                        newString += "7";
                        break;
                    case "&":
                        newString += "8";
                        break;
                    case "(":
                        newString += "9";
                        break;
                    case ")":
                        newString += "10";
                        break;
                    case "-":
                        newString += "11";
                        break;
                    case "_":
                        newString += "12";
                        break;
                    case "+":
                        newString += "13";
                        break;
                    case "=":
                        newString += "14";
                        break;
                    case "[":
                        newString += "15";
                        break;
                    case "]":
                        newString += "16";
                        break;
                    case "{":
                        newString += "17";
                        break;
                    case "}":
                        newString += "18";
                        break;
                    case "|":
                        newString += "19";
                        break;
                    case ":":
                        newString += "20";
                        break;
                    case ";":
                        newString += "21";
                        break;
                    case ".":
                        newString += "22";
                        break;
                    case ",":
                        newString += "23";
                        break;
                    case "'":
                        newString += "24";
                        break;
                    default:
                        newString += "99";
                        break;
                }
            }

            return newString;
        }

        public static string ConvertUrlsToLinks(string msg)
        {
            string[] words = msg.Split(new char[] { ' ' });
            foreach (string word in words)
            {
                // match youtube links
                if (Program.Window.checkSetting("youtubebot") == "1")
                {
                    Match regexMatch = Regex.Match(word, "^[^v]+v=(.{11}).*", RegexOptions.IgnoreCase);
                    if (regexMatch.Success)
                    {
                        return msg.Replace(word, "<a class=\"youtube\" href=\"http://www.youtube.com/v/" + regexMatch.Groups[1].Value + "&hl=en&fs=1\">" + word + "</a>");
                    }
                }

                // match images
                if (Program.Window.checkSetting("imagebot") == "1")
                {
                    Match regexMatch2 = Regex.Match(word, "^(http\\:\\/\\/[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,3}(?:\\/\\S*)?(?:[a-zA-Z0-9_])+\\.(?:jpg|jpeg|gif|png))$", RegexOptions.IgnoreCase);
                    if (regexMatch2.Success)
                    {
                        return msg.Replace(word, "<a class=\"image\" href=\"" + regexMatch2.Groups[1].Value + "\">" + regexMatch2.Groups[1].Value + "</a>");
                    }
                }

                // match youtube links (embed in chat)
                if (Program.Window.checkSetting("youtubeembed") == "1")
                {
                    Match regexMatch3 = Regex.Match(word, "^[^v]+v=(.{11}).*", RegexOptions.IgnoreCase);
                    if (regexMatch3.Success)
                    {
                        //return msg.Replace(word, "<a class=\"youtube\" href=\"http://www.youtube.com/v/" + regexMatch.Groups[1].Value + "&hl=en&fs=1\">" + word + "</a>");
                        return msg.Replace(word, "<div align=\"center\"><iframe title=\"YouTube video player\" width=\"460\" height=\"249\" src=\"http://www.youtube.com/embed/" + regexMatch3.Groups[1].Value + "\" frameborder=\"0\" allowfullscreen></iframe></div>");
                    }
                }

                // match images (embed in chat)
                if (Program.Window.checkSetting("imageembed") == "1")
                {
                    Match regexMatch4 = Regex.Match(word, "^(http\\:\\/\\/[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,3}(?:\\/\\S*)?(?:[a-zA-Z0-9_])+\\.(?:jpg|jpeg|gif|png))$", RegexOptions.IgnoreCase);
                    if (regexMatch4.Success)
                    {
                        return msg.Replace(word, "<div align=\"center\"><img class=\"resize\" src=\"" + regexMatch4.Groups[1].Value + "\" alt=\"Click to Resize\" title=\"Click to Resize\" /></div>");
                    }
                }
            }

            // match links (general)
            if (Program.Window.checkSetting("urllinks") == "1")
            {
                string regex = @"((www\.|(http|https|ftp|news|file)+\:\/\/)[&#95;.a-z0-9-]+\.[a-z0-9\/&#95;:@=.+?,##%&~-]*[^.|\'|\# |!|\(|?|,| |>|<|;|\)])";
                Regex r = new Regex(regex, RegexOptions.IgnoreCase);
                //return r.Replace(msg, "<a href=\"$1\" title=\"Click to open in a new window or tab\" target=\"&#95;blank\">$1</a>").Replace("href=\"www", "href=\"http://www");
                return r.Replace(msg, "<a href=\"$1\" title=\"Click to open in a new window or tab\">$1</a>").Replace("href=\"www", "href=\"http://www");
            }

            return msg;
        }

        public static string ReverseString(string s)
        {
            char[] arr = s.ToCharArray();
            Array.Reverse(arr);
            return new string(arr);
        }


        public static bool IsAlphaNumeric(String str)
        {
            Regex regexAlphaNum = new Regex("[^a-zA-Z0-9]");
            return !regexAlphaNum.IsMatch(str);
        }

        public static bool IsIllegal(string str)
        {
            str = str.Replace("@USEast", "").Replace("@USWest", "").Replace("@Europe", "").Replace("@Asia", "");

            if (str.Contains("#"))
            {
                string[] splt = str.Split('#');
                str = splt[0];
            }

            Regex regexIllegal = new Regex("([`~!$^&\\|\\+=;:{}@])");
            char[] arr = str.ToCharArray(0, str.Length);

            if (str.Length < 3 || !IsAlphaNumeric(arr[0].ToString()))
            {
                return true;
            }

            int isAlpha = 0;

            foreach (char c in arr)
            {
                if (IsAlphaNumeric(c.ToString()))
                {
                    isAlpha = 0;
                }
                else
                {
                    if (isAlpha == 1)
                    {
                        return true;
                    }

                    isAlpha = 1;
                }
            }
            
            return regexIllegal.IsMatch(str);
        }

        public static bool IsUppercase(string str)
        {
            //variable to hold our return value
            bool upper;
            //variable to hold our search pattern
            string pattern = "[a-z]";
            try
            {
                Regex AllCaps = new Regex(pattern);
                if (AllCaps.IsMatch(str))
                {
                    upper = false;
                }
                upper = true;
            }
            catch
            {
                upper = false;
            }
            return upper;
        }

        public static int RandomNumber(int min, int max)
        {
            Random random = new Random();
            return random.Next(min, max);
        }

        public static void BotLog(string server, string text)
        {
            StreamWriter SW;
            DateTime now = DateTime.Now;
            string file = string.Format("{0:MM-dd-yyyy}", now);
            string appPath = Path.GetDirectoryName(Application.ExecutablePath);
            string path = appPath + "\\logs\\" + server + "\\" + file + ".txt";
            
            SW = File.AppendText(path);
            SW.WriteLine("[" + now.ToString("T") + "] " + text);
            SW.Close();
        }
    }
    /* util */
}
